//
//  NSObject+Extension.swift
//  ThreeStone
//
//  Created by 王磊 on 1/28/17.
//  Copyright © 2017 ThreeStone. All rights reserved.
//

import UIKit

extension NSObject {
    //dict: 要进行转换的字典
    class func objectWithKeyValues(dict: NSDictionary) -> AnyObject? {
        
        if TSFoundation.isClassFromFoundation(self) {
            //            只有自定义模型类才可以字典转模型
            assert(true)
            return nil
        }
        
        let obj:AnyObject = self.init()
        
        var cls:AnyClass = self.classForCoder()                                           //当前类的类型
        
        while("NSObject" !=  "\(cls)"){
            var count:UInt32 = 0
            let properties =  class_copyPropertyList(cls, &count)                         //获取属性列表
            for i in 0..<count{
                
                let property = properties[Int(i)]                                         //获取模型中的某一个属性
                
                let propertyType = String.fromCString(property_getAttributes(property))!  //属性类型
                
                let propertyKey = String.fromCString(property_getName(property))!         //属性名称
                
                if propertyKey == "description"{ continue  }                              //description是Foundation中的计算型属性，是实例的描述信息
                
                var value:AnyObject! = dict[propertyKey]      //取得字典中的值
                
                if value == nil {continue}
                
                let valueType =  "\(value.classForCoder)"     //字典中保存的值得类型
                
                if valueType == "NSDictionary" {               //1，值是字典。 这个字典要对应一个自定义的模型类并且这个类不是Foundation中定义的类型。
                    if let subModelStr = TSFoundation.getType(propertyType) {
                        
                        if let subModelClass = NSClassFromString(subModelStr){
                            
                            value = subModelClass.objectWithKeyValues(value as! NSDictionary) //递归
                        }
                    } else {
                        
//                        printLog("你定义的模型与字典不匹配。 字典中的键\(propertyKey)  对应一个自定义的 模型")
                        
                        assert(true)
                        
                    }
                }else if valueType == "NSArray" {
                    //值是数组。 数组中存放字典。 将字典转换成模型。 如果协议中没有定义映射关系，就不做处理
                    //有的人喜欢用nsarray 有的人喜欢用Array<>
                    
                    if class_getClassMethod(cls, NSSelectorFromString("customClassMapping")) != nil {
                        if var subModelClassName = cls.customClassMapping()?[propertyKey] {   //子模型的类名称
                            
                            subModelClassName =  TSFoundation.bundlePath + "." + subModelClassName
                            
                            if let subModelClass = NSClassFromString(subModelClassName){
                                
                                value = subModelClass.objectArrayWithKeyValuesArray(value as! NSArray)
                            }
                        }
                        
                    }
                    
//                    NSObject
//                    
//                    let aaa : AnyObject! = 1
//                    
//                    aaa.conforms
                    
//                    if (cls as AnyObject).conformsToProtocol(DictModelProtocol.self) {
//                        
//                        let mapping = cls.customClassMapping()
//                        
//                        if !mapping!.isEmpty {
//                            if var subBeanClassName = mapping![propertyKey] {
//                                
//                                subBeanClassName =  TSFoundation.bundlePath + "." + subBeanClassName
//                                
//                                if let subBeanClass = NSClassFromString(subBeanClassName) {
//                                    
//                                    value = subBeanClass.objectArrayWithKeyValuesArray(value as! Array<AnyObject>) as! AnyObject
//                                }
//                                
//                            }
//                        }
//                        
//                    }
                    
                }
                // 如果值 是NSNumber 类型的 转换成 字符串
                if value is NSNumber {
                    
                    value = value.stringValue
                }
                
                //                printLog(value)
                
                if !(value is NSNull) {
                    
                    obj.setValue(value, forKey: propertyKey)
                    
                }
                
            }
            free(properties)                            //释放内存
            cls = cls.superclass()!                     //处理父类
        }
        return obj
    }
    class func objectArrayWithKeyValuesArray(array: NSArray) -> Array<AnyObject>? {
        if array.count == 0 {
            return nil
        }
        var result = [AnyObject]()
        
        for item in array {
            
            let type = "\(item.classForCoder)"
            
            if type == "NSDictionary" {
                if let model = objectWithKeyValues(item as! NSDictionary){
                    result.append(model)
                }
            }else if type == "NSArray"{
                if let model =  objectArrayWithKeyValuesArray(item as! NSArray){
                    result.append(model)
                }
            }else{
                result.append(item)
            }
        }
        if result.count==0{
            return nil
        }else{
            return result
        }
    }
}
extension NSObject {
    
    var keyValues:Dictionary<String,AnyObject>? {                   //获取一个模型对应的字典
        get{
            var result = [String: AnyObject]()           //保存结果
            var classType:AnyClass = classForCoder
            while("NSObject" !=  "\(classType)" ){
                var count:UInt32 = 0
                let properties = class_copyPropertyList(classType, &count)
                for i in 0..<count{
                    let property = properties[Int(i)]
                    let propertyKey = String.fromCString(property_getName(property))!         //模型中属性名称
                    let propertyType = String.fromCString(property_getAttributes(property))!  //模型中属性类型
                    
                    if "description" == propertyKey{ continue }   //描述，不是属性
                    
                    let tempValue:AnyObject!  = self.valueForKey(propertyKey)
                    if  tempValue == nil { continue }
                    
                    if let _ =  TSFoundation.getType(propertyType) {         //1,自定义的类
                        result[propertyKey] = tempValue.keyValues
                    } else if (propertyType.containsString("NSArray")){       //2, 数组, 将数组中的模型转成字典
                        result[propertyKey] = tempValue.keyValuesArray       //3， 基本数据
                    } else if (!propertyType.containsString("UIImage") && propertyKey != "server_Version" && !propertyType.containsString("CMDBSearchWorksTempParam") && !propertyType.containsString("CMDBSearchUserTempParam") ){
                        result[propertyKey] = tempValue
                    }
                }
                free(properties)
                classType = classType.superclass()!
            }
            if result.count == 0{
                return nil
            }else{
                //                printLog(result)
                
                return result
            }
        }
    }
}
extension NSArray {  //数组的拓展
    var keyValuesArray:Array<AnyObject>? {
        get{
            var result = [AnyObject]()
            for item in self{
                if !TSFoundation.isClassFromFoundation(item.classForCoder){ //1,自定义的类
                    let subKeyValues:[String:AnyObject]! = item.keyValues
                    if  subKeyValues == nil {continue}
                    result.append(subKeyValues)
                }else if item.classForCoder == NSArray.classForCoder(){    //2, 如果item 是数组
                    let subKeyValues:[AnyObject]! = item.keyValuesArray
                    if  subKeyValues == nil {continue}
                    result.append(subKeyValues)
                }else{                                                     //3, 基本数据类型
                    result.append(item)
                }
            }
            if result.count == 0{
                return nil
            }else{
                return result
            }
        }
    }
}


@objc public protocol DictModelProtocol {
    static func customClassMapping() -> [String: String]?
}
class TSFoundation {
    
    static let set = NSSet(array: [
        NSURL.classForCoder(),
        NSDate.classForCoder(),
        NSNumber.classForCoder(),
        NSValue.classForCoder(),
        NSData.classForCoder(),
        NSError.classForCoder(),
        NSDictionary.classForCoder(),
        NSString.classForCoder(),
        NSAttributedString.classForCoder()
        ])
    static let bundlePath = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
    
    /*** 判断某个类是否是 Foundation中自带的类 */
    static func isClassFromFoundation(c: AnyClass) -> Bool {
        var flag = false
        
        if c == NSObject.classForCoder() {
            flag = true
        } else {
            set.enumerateObjectsUsingBlock({ (foundation, stop) in
                
                if  c.isSubclassOfClass(foundation as! AnyClass) {
                    flag = true
                    stop.initialize(true)
                }
            })
        }
        return flag
    }
    /** 根据属性信息， 获得自定义类的 类名*/
    /**
     let propertyType = String.fromCString(property_getAttributes(property))! 获取属性类型
     到这个属性的类型是自定义的类时， 会得到下面的格式： T+@+"+..+工程的名字+数字+类名+"+,+其他,
     "T@\"_TtC10ThreeStone13TSAddressBean\",N,&,Vaddr"
     而我们想要的只是类名，所以要修改这个字符串
     */
    static func getType(code: String) -> String? {
        
        guard code.containsString(bundlePath) else {
            return nil
        }
        //        _TtC10ThreeStone13TSAddressBean
        var str = code.componentsSeparatedByString("\"")[1]
        
        guard let range = str.rangeOfString(bundlePath) else {
            
            return nil
        }
        
        str = str.substringFromIndex(range.endIndex)
        
        var numStr = "" //类名前面的数字
        
        for c:Character in str.characters {
            if c <= "9" && c >= "0"{
                numStr += String(c)
            }
        }
        
        guard let numRange = str.rangeOfString(numStr) else {
            return nil
        }
        str = str.substringFromIndex(numRange.endIndex)
        
        return bundlePath + "." + str
    }
}